package de.hsb.ai.util.map;

import game.Move;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.jgrapht.UndirectedGraph;
import org.jgrapht.graph.Multigraph;
import org.jgrapht.graph.UnmodifiableUndirectedGraph;

import de.hsb.ai.util.map.ScotlandJadeMapHelper.ScotlandJadeEdge;
import de.hsb.ai.util.map.ScotlandJadeMapHelper.ScotlandJadeVertex;
import de.hsb.ai.util.map.ScotlandJadeMapHelper.ScotlandJadeVertexImpl;

/**
 * ScotlandJadeMap represents the board with all nodes/vertices and links/edges. 
 */
@SuppressWarnings("serial")
public class ScotlandJadeMap 
extends UnmodifiableUndirectedGraph<ScotlandJadeVertex, ScotlandJadeEdge>
implements Cloneable {
	
	private final List<ScotlandJadeVertex> indexedVertices;

	static ScotlandJadeMap create(int vertexCount, Set<ScotlandJadeEdge> edges) {
		UndirectedGraph<ScotlandJadeVertex, ScotlandJadeEdge> base = new Multigraph<ScotlandJadeVertex, ScotlandJadeEdge>(ScotlandJadeEdge.class);
		List<ScotlandJadeVertex> indexedVertices = new ArrayList<ScotlandJadeVertex>(vertexCount);
		for (int i = 0; i < vertexCount; ++i) {
			ScotlandJadeVertex vertex = new ScotlandJadeVertexImpl(i);
			indexedVertices.add(vertex);
			base.addVertex(vertex);
		}
		for (ScotlandJadeEdge edge : edges) {
			base.addEdge(
					indexedVertices.get(edge.getSourceIndex()), 
					indexedVertices.get(edge.getTargetIndex()), edge);
		}
		
		return new ScotlandJadeMap(base, indexedVertices);
	}
	
	protected ScotlandJadeMap(UndirectedGraph<ScotlandJadeVertex, ScotlandJadeEdge> graph, List<ScotlandJadeVertex> indexedVertices) {
		super(graph);
		this.indexedVertices = indexedVertices;
	}
	
	/**
	 * Retraces the specified move in the graph.
	 * Assumes that the vertex at {@code from} has the correct
	 * occupation/{@link ScotlandJadeVertex.Type vertex-type}.
	 * @param from vetex index to start from
	 * @param move move to be retraced
	 */
	public ScotlandJadeVertex move(int from, Move move) {
		return move(from, move.getNode());
	}
	
	public ScotlandJadeVertex move(int from, int to) {
		ScotlandJadeVertex source = get(from);
		ScotlandJadeVertex target = get(to);
		
		if (!target.equals(source)) {
			target.setType(source.getType());
			source.setType(ScotlandJadeVertex.DEFAULT_TYPE);
		}
		
		return target;
	}
	
	public ScotlandJadeEdge getEdge(ScotlandJadeVertex sourceVertex, ScotlandJadeVertex targetVertex, int transport) {
		for (ScotlandJadeEdge edge : super.getAllEdges(sourceVertex, targetVertex)) {
			if (edge.getType() == transport) return edge;			
		}
		return null;
	}
	
	/**
	 * Returns the vertex at the specified index.
	 * @param index the vertex index
	 * @return the vertex at {@code index}
	 * @throws IndexOutOfBoundsException if no vertex with the specified index can be found
	 */
	public ScotlandJadeVertex get(int index) {
		return indexedVertices.get(index);
	}

	/**
	 * Resets all vertices to {@link ScotlandJadeVertex#DEFAULT_TYPE}.
	 */
	public void reset() {
		for (ScotlandJadeVertex v : vertexSet()) {
			v.setType(ScotlandJadeVertex.DEFAULT_TYPE);
		}
	}

}
